package com.szw.dlyk.config.filter;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.szw.dlyk.constant.Constant;
import com.szw.dlyk.domain.User;
import com.szw.dlyk.dto.UserDtoLogin;
import com.szw.dlyk.result.CodeEnum;
import com.szw.dlyk.result.Result;
import com.szw.dlyk.service.RedisService;
import com.szw.dlyk.util.JwtUtil;
import com.szw.dlyk.util.ResponseUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;


@Component
public class TokenVerifyFilter extends OncePerRequestFilter {

    @Resource
    private RedisService redisService;

    /**
     * spring boot框架的ioc容器中已经创建好了该线程池，可以注入直接使用
     */
    @Resource
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        //如果是登录请求，此时还没有生成jwt，那不需要对登录请求进行jwt验证
        if (request.getRequestURI().equals(Constant.LOGIN_URL)) {
            //验证jwt通过了 ，让Filter链继续执行，也就是继续执行下一个Filter
            filterChain.doFilter(request, response);
        } else {
            String token = null;
            if (request.getRequestURI().equals(Constant.EXPORT_EXCEL_URI)) {
                //从请求路径的参数中获取token
                token = request.getParameter("Authorization");
            } else {
                //其他请求都是从请求头中获取token
                token = request.getHeader("Authorization");
            }

            if (!StrUtil.isNotBlank(token)){
                Result result = Result.fail(CodeEnum.TOKEN_IS_EMPTY);
                String s = JSONUtil.toJsonStr(result);
                ResponseUtils.write(response,s);
                return;
            }

            if (!JwtUtil.verifyJWT(token)){
                Result result = Result.fail(CodeEnum.TOKEN_IS_ERROR);
                String s = JSONUtil.toJsonStr(result);
                ResponseUtils.write(response,s);
                return;
            }

            User user = JwtUtil.parseUserFromJWT(token);
            String redisToken = (String) redisService.getValue(Constant.REDIS_JWT_KEY + user.getId());

            if (!StrUtil.isNotBlank(redisToken)){
                Result result = Result.fail(CodeEnum.TOKEN_IS_EXPIRED);
                String s = JSONUtil.toJsonStr(result);
                ResponseUtils.write(response,s);
                return;
            }

            if (!token.equals(redisToken)){
                Result result = Result.fail(CodeEnum.TOKEN_IS_NONE_MATCH);
                String s = JSONUtil.toJsonStr(result);
                ResponseUtils.write(response,s);
                return;
            }

            UserDtoLogin userDtoLogin = BeanUtil.copyProperties(user, UserDtoLogin.class);
            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userDtoLogin, userDtoLogin.getLoginPwd(), userDtoLogin.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);

            //刷新一下token （异步）
            threadPoolTaskExecutor.execute(()->{
                String rememberMe = request.getHeader("rememberMe");
                if (Boolean.parseBoolean(rememberMe)) {
                    redisService.expire(Constant.REDIS_JWT_KEY + user.getId(),Constant.EXPIRE_TIME,TimeUnit.SECONDS);
                }else {
                    redisService.expire(Constant.REDIS_JWT_KEY + user.getId(),Constant.DEFAULT_EXPIRE_TIME,TimeUnit.SECONDS);
                }
            });
            filterChain.doFilter(request,response);
        }
    }
}
